#include "s3c2440.h"
#include "uart.h"
#include "nandflash.h"

//nfbool:1 enable nandflash; 0 disable nandflash
#define  NF_ENABLE()	(NFCONT &= ~(1 << 1))
#define  NF_DISABLE()	(NFCONT |= (1 << 1))

#define  HD_LOCK()		(NFCONT |= (1 << 13))		//enable lock-tight
#define	 HD_UNLOCK()	(NFCONT &= ~(1 << 13))		//disable lock-tight

#define  SF_LOCK()		(NFCONT |= (1 << 12))		//enable soft lock
#define  SF_UNLOCK()	(NFCONT &= ~(1 << 12))		//disaBLE soft lock

#define  SECC_LOCK()	(NFCONT |= (1 << 6))		//lock Spare ECC status register
#define  SECC_UNLOCK()	(NFCONT &= ~(1 << 6))		//unlock Spare ECC 

#define  MECC_LOCK()	(NFCONT |= (1 << 6))		//lock Main ECC
#define  MECC_UNLOCK()	(NFCONT &= ~(1 << 6))		//unlcokc main ecc
#define  WR_CMD(cmd)	(NFCMMD = (cmd))
#define  WR_ADDR(addr)	(NFADDR = (addr))
#define  WR_BYTE(nfdata) (NFDATA8 = (nfdata))
#define  RD_BYTE()		(NFDATA8) 


#define  RnB			(NFSTAT & 0X01)

void flashinit(void)
{
	
	// TACLS = 3; TWRPH0 = 6; TWRPH1 = 6;
	NFCONF = (3 << 12) | (0x6 << 8) | (6 << 4);

	/*
	DISALBE lock-tight;disable soft lock;
	disable illegal access interrupt ;
	disable RnB interrupt;
	Detect rising edge of RnB
	unlock spare ecc
	unlock main data area
	initialize ecc
	enable chip select
	enable flash controller
	*/
	NFCONT = 0X11;
}

void delay(unsigned int i)
{	
	unsigned j;
	j = i;
	while(j--);
}
unsigned int nf_readid(void)
{
	unsigned int id;

	
	WR_CMD(0x90);
	WR_ADDR(0x00);
	
//	NFADDR = 0x00;
	while((NFSTAT & 0x01) == 0x00);

	id = NFDATA;
	return id;
}

unsigned char nf_readstat(void)
{
	NF_ENABLE();
	WR_CMD(0X70);
	while(RnB == 0);		//wait until nandflash is ready
	return RD_BYTE();
	NF_DISABLE();
	
}

void nf_check_blk(void)
{
	
}

unsigned char nf_readcolumn(unsigned char half_sel,unsigned int addr)
{
	unsigned char tmp;
	NF_ENABLE();
	if(half_sel == 0)
	{
		WR_CMD(0X00);
		}
	else if(half_sel == 1)
		{
		WR_CMD(0x01);
		}
	else if(half_sel == 2)
		{
		WR_CMD(0x50);
		}
	else
		{
		puts("wrong cmd\n\r");
		}
	
	WR_ADDR(addr);
	WR_ADDR(addr >> 8);
	WR_ADDR(addr >> 16);
	WR_ADDR(addr >> 24);
	while(RnB == 0);		//this comment is needed
	tmp = RD_BYTE();
	NF_DISABLE();
	return tmp;		
}

void nf_readpage(unsigned int pageaddr,unsigned char *buf)//pageaddr:0~32767
{
	unsigned int i;
	NF_ENABLE();
	WR_CMD(00);
	WR_ADDR(0);
	WR_ADDR(pageaddr);
	WR_ADDR(pageaddr >> 8);
	WR_ADDR(pageaddr >> 16);
	while(RnB == 0);

	for(i = 0; i < 512; i ++)
		{
		*buf = RD_BYTE();
		buf++;
		}
	NF_DISABLE();
}

void nf_writepage(unsigned int pageaddr,unsigned char *buf)	 //pageaddr:0~32767
{
	unsigned int i;
	NF_ENABLE();
	WR_CMD(00);
	WR_CMD(0X80);
	WR_ADDR(0);
	WR_ADDR(pageaddr);
	WR_ADDR(pageaddr >> 8);
	WR_ADDR(pageaddr >> 16);
	
	for(i = 0; i < 512; i++) 
	{
		WR_BYTE(*buf);
		buf++;
		
	}
	WR_CMD(0X10);
	
	while(RnB == 0);

	if((nf_readstat() & 0x01) == 00)
		{
			puts("page program is ok\n\r");
		}	
		else
		
		{
			puts("page program fail\n\r");
			}
	NF_DISABLE();
}

void nf_eraseblk(unsigned int blkaddr)  //blckaddr : 0~4095
{
	NF_ENABLE();
	WR_CMD(0X60);
	//WR_ADDR(0X00);
	WR_ADDR(blkaddr << 5);
	WR_ADDR(blkaddr >> 3);
	WR_ADDR(blkaddr >> 11);
	WR_CMD(0XD0);

	while(RnB == 0);

	WR_CMD(0X70);
	if((RD_BYTE() & 0x01) == 0x00)
		{
			puts("eraser is ok\n\r");
		}
	else
		
		{
			puts("eraser fail\n\r");
			}
	NF_DISABLE();
}

void nf_copyback(unsigned int srcaddr,unsigned int dstaddr)
{
	NF_ENABLE();
	WR_CMD(0X00);
	
	WR_ADDR(0X00);
	WR_ADDR(srcaddr);
	WR_ADDR(srcaddr >> 8);
	WR_ADDR(srcaddr >> 16);
	while(RnB == 0);
	
	WR_CMD(0X8A);
	WR_ADDR(00);
	WR_ADDR(dstaddr);
	WR_ADDR(dstaddr >> 8);
	WR_ADDR(dstaddr >> 16);
	
	WR_CMD(0X10);
	while(RnB == 0);
	
	WR_CMD(0X70);
	if((nf_readstat() & 0x01) == 0x00)
	{
		puts("copy back program is ok\n\r");
	}
	else
		
		{
			puts("copy back fail\n\r");
			}
	NF_DISABLE();
}
	

